package gui;

import java.util.ArrayList;
import java.util.Calendar;

import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

import business.BusinessImpl;
import constant.Constant;
import dto.DTOAbsence;
import dto.DTOClass;
import dto.DTOContact;

/**
 * @author Jonathan Maret
 * This class extends JTable and is used to manage absence
 * This class used periodmodel as a AbstractTableModel
 */
public class TablePeriod extends JTable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Calendar selectedDate;
	private DTOClass selectedClass;
	private  Object[][] data;
	private BusinessImpl businessImpl = new BusinessImpl();
	
	public TablePeriod() {
		super();
	}
	
	public TablePeriod(DTOClass clasS, Calendar selectedDate) {
		super();
		refreshData(clasS, selectedDate);
	}

	/**
	 *  Format the table, define the width of each column, the combo box into the typeofabsence column 
	 */
	private void formatTable (){
		for (int i = 1; i < this.getColumnCount()-1; i++) {
			if(i>1 && i< this.getColumnCount()-1){
				this.getColumnModel().getColumn(i).setPreferredWidth(20);
				this.getColumnModel().getColumn(i).setMaxWidth(20);
				this.getColumnModel().getColumn(i).setMinWidth(20);}
		}

		this.getColumnModel().getColumn(1).setPreferredWidth(100);
		this.getColumnModel().getColumn(1).setMaxWidth(100);
		this.getColumnModel().getColumn(1).setMinWidth(100);	

		TableColumn AbsenceTypeColumn = this.getColumnModel().getColumn(1);
		JComboBox comboBox = new JComboBox();
		comboBox.addItem("Non-Excusé");
		comboBox.addItem("Excusé");
		AbsenceTypeColumn.setCellEditor(new DefaultCellEditor(comboBox));

		this.getColumnModel().getColumn(0).setPreferredWidth(150);
		this.getColumnModel().getColumn(0).setMaxWidth(150);
		this.getColumnModel().getColumn(0).setMinWidth(150);	

		

	}

	/**
	 * Refresh the data into the table for a class at a specified date
	 * Add a tablemodelListener to call refreshtable(e)
	 * @param clasS
	 * @param selectedDate
	 */
	public void refreshData(DTOClass clasS, final Calendar selectedDate){

		this.selectedClass = clasS;
		this.selectedDate = selectedDate;
		data = getFormatedTableData(selectedClass);

		if(data!= null){
		PeriodModel periodModel  = new PeriodModel(data);
		this.setModel(periodModel);
		
		this.removeColumn(this.getColumnModel().getColumn(0));
		this.getModel().addTableModelListener(new TableModelListener() {
			
			@Override
			public void tableChanged(TableModelEvent e) {

				refreshTable(e);
				
			}
		});


		formatTable();
		}
		else
		this.setModel(new DefaultTableModel());
	}

	/**
	 * Event occurring when the user change the value of a column, update the table then ask the business to update the database
	 * @param e
	 */
	private void refreshTable(TableModelEvent e){
		if (e.getSource() instanceof PeriodModel) {
			PeriodModel periodmodel = (PeriodModel) e.getSource();
			String formatedPeriod = "";
			int typeOfAbsence = 0;
			String comment = "";
			if(e.getFirstRow() >-1){
				if (e.getColumn() >= Constant.TABLE_ABSENCE_DEFAULT_HEADER_LENGHT)
					// Correct the data according to the user change if the user change an absence will update all following absence
					for (int i = e.getColumn(); i < Constant.PERIOD_NUMBER_DEFAULT
							+ Constant.TABLE_ABSENCE_DEFAULT_HEADER_LENGHT; i++) {
						data[e.getFirstRow()][i] = periodmodel.getData()[e
						                                                 .getFirstRow()][e.getColumn()];

					}

				// Format each boolean field into a string to save a period field
				for (int i = 0; i < Constant.PERIOD_NUMBER_DEFAULT; i++) {
					formatedPeriod += Integer.toString(((boolean) data[e.getFirstRow()][i+ Constant.TABLE_ABSENCE_DEFAULT_HEADER_LENGHT]) ? 1
							: 0);
				}

				// Ask the business to update the database
				if (periodmodel.getData()[e.getFirstRow()][0] instanceof DTOContact) {
					DTOContact student = (DTOContact) periodmodel.getData()[e
					                                                        .getFirstRow()][0];
					// Test the type of absence
					if (periodmodel.getData()[e.getFirstRow()][2] instanceof String) {
						String temp = (String) periodmodel.getData()[e
						                                             .getFirstRow()][2];
						data[e.getFirstRow()][2] = temp;

						if (temp == "Excusé")
							typeOfAbsence = 1;
						else
							typeOfAbsence = 0;
					}

					// Test the comment
					if (periodmodel.getData()[e.getFirstRow()][periodmodel
					                                           .getColumnCount() - 1] instanceof String) {
						String temp = (String) periodmodel.getData()[e
						                                             .getFirstRow()][periodmodel
						                                                             .getColumnCount() - 1];
						data[e.getFirstRow()][periodmodel.getColumnCount() - 1] = temp;
						comment = temp;
					}

					businessImpl.updateAbsence(student,
							selectedDate,
							new DTOAbsence(0, 0, selectedDate.getTime(),
									formatedPeriod, typeOfAbsence, comment,false));

				}
				// refresh the table
				this.refreshData(selectedClass,selectedDate);
				this.repaint();
			}
			

		}

	}
	
	/**
	 * Format the data to display into the table
	 * @param clasS
	 * @return The data ready to be placed into the tableperiod
	 */
	private Object[][] getFormatedTableData(DTOClass clasS) {

		ArrayList<DTOContact> contacts = businessImpl.getContactsByClass(clasS);
		ArrayList<ArrayList<Object>> object = new ArrayList<ArrayList<Object>>();

		for (int i = 0; i < contacts.size(); i++) {

			if (contacts.get(i).getTypeOfContact() == Constant
					.typeofcontact("STUDENT")) {
				ArrayList<Object> temp = new ArrayList<Object>();

				// Add a column with the contact, and a second with a
				// formated name
				temp.add(contacts.get(i));
				temp.add(contacts.get(i).toString());

				String period;
				DTOAbsence absence = businessImpl.getAbsenceByContactByDate(
						contacts.get(i), selectedDate);

				// Add each column for each period
				if (absence != null) {

					if (absence.getTypeOfAbsence() == 1)
						temp.add("Excusé");
					else
						temp.add("Non-excusé");

					period = absence.getPeriod();
				} else {
					temp.add("Non-excusé");
					period = Constant.TABLE_ABSENCE_DEFAULT_PERIOD;
				}

				for (int j = 0; j < period.length(); j++) {
					if (Integer.parseInt(period.substring(j, j + 1)) != 0)
						temp.add(true);
					else
						temp.add(false);
				}

				if (absence != null)
					temp.add(absence.getComment());
				else
					temp.add("");

				object.add(temp);
			}

		}
		Object[][] ret = null;
		if(object.size() > 0){
		ret = new Object[object.size()][object.get(0).size()];

		for (int i = 0; i < object.size(); i++) {
			for (int j = 0; j < object.get(i).size(); j++) {
				ret[i][j] = object.get(i).get(j);
			}
		}
		}
		return ret;
	}



}
